package multithreading;

import java.util.LinkedList;

/**
 * 线程池
 * ThreadGroup      线程组（池），可对线程进行批量管理
 *                  如果在new Thread时没有显示指定线程组，
 *                  则默认将父线程（当前执行new Thread的线程）的线程组设置为新建线程的线程组
 *
 * public ThreadGroup(String name)      参数name表示新线程组的名称
 * public ThreadGroup(ThreadGroup parent, String name)      参数parent表示父线程组，参数name表示新线程组的名称
 *
 * // 获取当前线程所在线程组的活动线程总数(估计)。
 * threadGroup.activeCount()  //或者下面的方法
 * Thread.activeCount()
 *
 * //获取该线程组的父线程组
 * threadGroup.getParent()
 *
 * //获取当前线程所属线程组
 * Thread.currentThread().getThreadGroup()
 *
 * ThreadGroup.setDaemon(boolean daemon)    方法改变该线程组的守护进程的状态
 *                                          当其最后一个线程被停止或它的最后一个线程组被销毁守护线程组会自动销毁
 *
 * ThreadGroup.interrupt()      中断线程组中的所有工作线程
 *
 * ThreadGroup.enumerate(Thread[] threadArray)  将线程组中当前所有活着的工作线程复制到指定的数组中，并返回放入数组的线程数
 * */
public class ThreadPool extends ThreadGroup {
    private boolean isClosed = false;   // 线程池是否关闭
    private LinkedList<Runnable> workQueue;     // 工作队列
    private static int threadPoolID;    // 线程池ID
    private int threadID;       // 工作线程ID

    public ThreadPool(int poolSize) { // poolSize指定线程池中工作线程数目
        super("ThreadPool-" + (threadPoolID++));
        setDaemon(true);    // 设置线程池为守护线程池
        workQueue = new LinkedList<>();     // 创建工作队列
        for (int i = 0; i < poolSize; i++)
            new WorkThread().start();       // 创建并启动工作线程
    }

    /**
     * 向工作队列中加入一个新任务，由工作线程去执行该任务
     * 使用synchronized
     * 同步方法，锁是本类this（类锁）
     * */
    public synchronized void execute(Runnable task){
        if (isClosed)   // 线程池被关闭则抛出IllegalStateException异常（非法状态异常）
            throw new IllegalStateException();
        if (task != null) {
            workQueue.add(task);
            notify();   // 唤醒正在getTask()方法中等待任务的工作线程
        }
    }

    /**
     * 从工作队列中取出一个任务，工作线程会调用此方法
     * */
    protected synchronized Runnable getTask() throws InterruptedException {
        while (workQueue.size() == 0) {
            if (isClosed)
                return null;    // 线程池关闭则返回null
            wait();     // 如果工作队列中没有任务则等待任务
        }
        return workQueue.removeFirst();     // 移除并返回工作队列中的第一个任务
    }

    /** 关闭线程池 */
    public synchronized void close() {
        if (!isClosed) {
            isClosed = true;
            workQueue.clear();      // 清空工作队列
            interrupt();    //中断所有的工作线程，该方法继承自TheadGroup类
        }
    }

    /** 等待工作线程把所有任务执行完 */
    public void join() {
        synchronized(this) {
            isClosed = true;
            notifyAll();    // 唤醒还在getTask()方法中等待任务的工作线程
        }
        Thread[] threads = new Thread[activeCount()];
        int count = enumerate(threads);     // 获取线程池中当前所有或者的工作线程并放入数组中
        for (int i = 0; i < count; i++)   // 等待所有工作线程运行结束
            try {
                threads[i].join();      // 等待工作线程运行结束
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    /**
     * 内部类          工作线程
     * 可访问外部类的成员变量和方法
     * */
    private class WorkThread extends Thread {
        public WorkThread() {
            // 加入当前TreadPool线程组中
            super(ThreadPool.this, "WorkThread-" + (threadID++));
        }

        @Override
        public void run() {
            while (!isInterrupted()) {
                Runnable task = null;
                try {
                    task = getTask();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (task == null)
                    return;     // 如果getTask()返回null或线程执行getTask()时被中断则结束此线程
                try {   // 执行任务，异常在catch代码块中被捕获
                    task.run();
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        }
    }
}

class ThreadPoolTester {
    public static void main(String[] args) {
//        if (args.length != 2) {
//            System.out.println("用法：java ThreadPoolTest numTasks poolSize");
//            System.out.println("  numTasks - integer：任务的数目");
//            System.out.println("  numThreads - integer：线程池中的线程数目");
//            return;
//        }
//        int nunTasks = Integer.parseInt(args[0]);
//        int poolSize = Integer.parseInt(args[1]);
        int nunTasks = 100;
        int poolSize = 10;
        ThreadPool threadPool = new ThreadPool(poolSize);   // 创建线程池
        for (int i = 1; i <= nunTasks; i++)
            threadPool.execute(createTask(i));  // 创建并运行任务
        threadPool.join();      // 等待工作线程完成所有的任务
//        try {
//            Thread.sleep(10000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        threadPool.close();     // 关闭线程池
    }

    private static Runnable createTask(final int taskID) {  // 创建任务
        return new Runnable() {
            @Override
            public void run() {
                System.out.println("Task " + taskID + ": start");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskID + ": end");
            }
        };
    }
}